<!-- Created by henian.xu on 2017/6/6. -->
<template>
    <el-table
        class="tree-grid"
        v-bind="$attrs"
        :data="this.tableData"
    >
        <el-table-column
            class-name="column-expand"
            v-if="!!this.expandProp"
            :prop="this.expandProp.prop"
            :label="this.expandProp.label"
            :width="this.expandProp.width"
            :min-width="this.expandProp.minWidth"
        >
            <template slot-scope="scope">
                <div
                    :class="['indent-space',{'leaf':scope.row[props.isLeaf]}]"
                    :style="{
                        'padding-left':(14 * scope.row[props.level]) + 'px'
                    }"
                    @click="onExpand(scope.$index, scope.row, scope)"
                >
                    <i
                        v-if="!scope.row[props.isLeaf]"
                        :class="{
                            'el-icon-caret-right':!scope.row[props.expand],
                            'el-icon-caret-bottom':scope.row[props.expand]
                        }"
                    />
                    <i
                        v-else
                        class="el-icon-caret-right"
                        style="opacity: 0"
                    />
                    <div class="node-label">{{ scope.row[expandProp.prop] }}</div>
                </div>
            </template>
        </el-table-column>

        <slot/>
    </el-table>
</template>

<script>
export default {
    name: 'TreeTable',
    data() {
        return {
            tableData: this.data,
            rootNode: {
                $index: -1,
                row: {
                    _loaded: true,
                    [this.props.expand]: true,
                    [this.props.children]: this.data,
                },
                _self: this,
            },
        };
    },
    props: {
        data: {
            type: Array,
            default() {
                return [];
            },
        },
        expandProp: {
            type: Object,
            default() {
                return null;
            },
        },
        props: {
            type: Object,
            default() {
                return {
                    children: 'children',
                    expand: 'expand',
                    level: 'lv',
                    isLeaf: 'isLeaf',
                };
            },
        },
        rootNodeLevel: {
            type: Number,
            default: 1,
        },
        lazy: {
            type: Boolean,
            default: false,
        },
        load: {
            type: Function,
            default() {
                return null;
            },
        }, // Promise
    },
    methods: {
        // 数据变换
        dataTranslate(data, level = this.rootNodeLevel) {
            if (!Array.isArray(data)) return;
            data.forEach(item => {
                item[this.props.expand] = !!item[this.props.expand];
                if (item[this.props.isLeaf] === undefined) {
                    item[this.props.isLeaf] = true;
                }
                item[this.props.children] = item[this.props.children] || [];
                item[this.props.level] = item[this.props.level] || level;
                this.dataTranslate(item[this.props.children], level + 1);
            });
        },
        // 展开行数据变换(获取节点下所有已展开的子节点)(算法代优化)
        expandRowDataTranslate: (() => {
            let _row = [];

            function fn(row, reset = true) {
                if (reset) _row = [];
                row.forEach(item => {
                    _row.push(item);
                    const children = item[this.props.children];
                    if (item[this.props.isLeaf] || !item[this.props.expand] || !children.length) return;
                    return fn.call(this, children, false);
                });
                return _row;
            }

            return fn;
        })(),
        onExpand(index, row, scope) {
            if (row[this.props.isLeaf]) return;
            const { lazy, load: loadFn } = this;
            if (lazy && loadFn) {
                const rowIsArr = Array.isArray(row);
                if (!row['_loaded']) {
                    loadFn({ scope }).then(result => {
                        this.dataTranslate(result, index + 1);
                        let childre = row;
                        if (!rowIsArr) {
                            childre = row.children || (row.children = []);
                            row['_loaded'] = true;
                        }
                        result.forEach(item => {
                            childre.push(item);
                        });
                        if (!rowIsArr) {
                            this.expandFold(index, row, scope);
                        }
                    });
                } else {
                    this.expandFold(index, row, scope);
                }
            } else {
                this.expandFold(index, row, scope);
            }
        },
        // 展开或收缩节点(算法代优化)
        expandFold(index, row, scope) {
            const children = this.expandRowDataTranslate(row[this.props.children]);
            if (!row[this.props.expand]) {
                row[this.props.expand] = true;
                children.reverse(); // 倒序
                children.forEach(item => {
                    if (item._parent === undefined) {
                        item._parent = scope;
                    }
                    this.tableData.splice(index + 1, 0, item);
                });
            } else {
                row[this.props.expand] = false;
                this.tableData.splice(index + 1, children.length);
            }
        },
        // 刷新子节点 index,row 必须是对应的
        refreshChildren(index, row) {
            if (!row[this.props.expand]) return;
            let _c = [];
            if (row === this.rootNode.row) {
                row[this.props.children].forEach(item => {
                    if (item[this.props.level] !== this.rootNodeLevel) return;
                    _c.push(item);
                });
            } else {
                _c = row[this.props.children];
            }
            const children = this.expandRowDataTranslate(_c);
            this.tableData.splice(index + 1, children.length);
            children.reverse(); // 倒序
            children.forEach(item => {
                this.tableData.splice(index + 1, 0, item);
            });
        },
        /**
         * 增加子节点
         * @param index
         * @param row 类型是 {} 时会插入到 {}.children里，[] 时直接插入
         * @param data Array
         */
        add(scope, data) {
            if (!data.length) return;
            this.dataTranslate(data, scope.$index + 1);
            scope.row[this.props.isLeaf] = false;
            if (scope.row['_loaded']) {
                const index = this.tableData.indexOf(scope.row);
                const children = this.expandRowDataTranslate(scope.row[this.props.children]);
                data.forEach(item => {
                    if (item[this.props.level] !== this.rootNodeLevel) {
                        item._parent = scope;
                        this.tableData.splice(index + children.length + 1, 0, item);
                    }
                    scope.row[this.props.children].push(item);
                });
            }
        },
        remove(row) {
            if (row._parent) {
                const Prow = row._parent.row;
                const ProwChildren = Prow[this.props.children];
                const index = ProwChildren.indexOf(row);
                const index2 = this.tableData.indexOf(row);
                if (index === -1 || index2 === -1) {
                    throw new Error('节点不在');
                }
                const children = this.expandRowDataTranslate(row[this.props.children]);
                this.tableData.splice(index2, children.length + 1);
                ProwChildren.splice(index, 1);
            } else {
                const index = this.tableData.indexOf(row);
                const children = this.expandRowDataTranslate(row[this.props.children]);
                this.tableData.splice(index, children.length + 1);
            }
        },
        /**
         * lazy 为真时此方法会立即调用 loadNode方法
         * @param data 如果 lazy 为真此参数无用
         */
        upDataRoot(data) {
            return new Promise((resolve, reject) => {
                const { lazy, load: loadFn } = this;
                if (lazy && loadFn) {
                    this.tableData.splice(0, this.tableData.length);
                    loadFn()
                        .then(result => {
                            console.log(1);
                            this.dataTranslate(result);
                            result.forEach(item => {
                                this.tableData.push(item);
                            });
                            resolve();
                        })
                        .catch(reject);
                } else {
                    this.tableData = this.dataTranslate(data);
                    resolve();
                }
            });
        },
    },
    mounted() {
        // if (!this.tableData.length && this.lazy) {
        //     this.onExpand(0, this.tableData, {});
        // } else {
        this.dataTranslate(this.tableData);
        this.lazy && this.upDataRoot();
        // }
        // console.log(this.$attrs);
        // console.log(this.$props);
        // console.log(this.$listeners);
    },
};
</script>

<style lang="scss" scoped>
.tree-grid {
    td.column-expand {
        > .cell {
            padding-left: 5px;
            .indent-space {
                @include clearfix;
                &:not(.leaf) {
                    cursor: pointer;
                }
                > [class^='el-icon-'] {
                    float: left;
                    color: #97a8be;
                    margin: 5px 5px 5px 0;
                }
                > .node-label {
                    overflow: hidden;
                }
            }
        }
    }
}
</style>
